/*
 * Copyright (c) 2021 Talkweb Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include "ohos_init.h"
#include "cmsis_os2.h"

#include "iot_gpio.h"
#include "iot_adc.h"
#include "iot_errno.h"

#define TASK_STACK_SIZE 1024
#define TASK_PRIO 25

#define BATTERYCHARGEMAX 4.2 //电池充电过压阈值
#define BATTERYCHARGEMIN 2.8 //电池低电压报警阈值

//申明相关oled API函数
extern void OledIICInit(void);
extern void OledRefresh(void);
extern void OledShowString(unsigned char x, unsigned char y, char *chr, unsigned char size1);

//开启电池充电
static void BatteryChargeStart(void)
{
    IoTGpioSetOutputVal(IOT_GPIO_IO_GPIO_6, IOT_GPIO_VALUE0);
}

//停止电池充电
static void BatteryChargeStop(void)
{
    IoTGpioSetOutputVal(IOT_GPIO_IO_GPIO_6, IOT_GPIO_VALUE1);
}

static void BatteryTask(void)
{
    int ret = 0;
    char pbuf[10] = {0};
    unsigned short adVal = 0;
    unsigned char chargeState = 0;
    float voltage = 0, vBat = 0;

    //充电控制脚
    IoTGpioInit(IOT_GPIO_IO_GPIO_6);
    IoTIoSetFunc(IOT_GPIO_IO_GPIO_6, IOT_IO_FUNC_GPIO_6_GPIO);
    IoTGpioSetDir(IOT_GPIO_IO_GPIO_6, IOT_GPIO_DIR_OUT);
    IoTGpioSetOutputVal(IOT_GPIO_IO_GPIO_6, IOT_GPIO_VALUE0);

    //AD检测引脚初始化为浮夸模式
    IoTGpioInit(IOT_GPIO_IO_GPIO_9);
    IoTIoSetPull(IOT_GPIO_IO_GPIO_9, IOT_IO_PULL_NONE);

    //OLED初始化
    OledIICInit();

    //Oled显示初始固定字符
    OledShowString(3, 3, "adcVol:    V", 16);
    OledShowString(3, 23, "batVol:    V", 16);
    OledShowString(3, 43, "charge:", 16);
    OledRefresh();

    for (;;)
    {
        //获取电压采集值
        ret = IoTAdcRead(IOT_ADC_CHANNEL_4, &adVal, IOT_ADC_EQU_MODEL_8, IOT_ADC_CUR_BAIS_DEFAULT, 256);
        if (ret != IOT_SUCCESS)
        {
            printf("Failed to read adc! Err code = %d\r\n", ret);
            continue;
        }

        //将AD值转换成电压值
        voltage = IOTAdcConvertToVoltage(adVal);

        //根据采集的电压值，推算出VBat目前的供电电压
        vBat = (voltage * 1510) / 510;

        printf("state = %u, adVal = %u, adVol = %.02f, batVol = %.02f \r\n", chargeState, adVal, voltage, vBat);

        //当供电电压大于保护电压阈值时，断开充电
        if (vBat >= BATTERYCHARGEMAX)
        {
            BatteryChargeStop();
            chargeState = 0;
        }

        //当供电电压小于低电压报警阈值时，提示报警并做一些其它紧急的事情
        else if (vBat <= BATTERYCHARGEMIN)
        {
            printf("the voltage is too low！！！\r\n");
            BatteryChargeStart();
            chargeState = 1;
            //do something
        }

        //正常充电范围内进行充电处理
        else
        {
            BatteryChargeStart();
            chargeState = 1;
        }

        //Oled显示adc采集电压
        sprintf((char *)pbuf, "%0.2f", voltage);
        OledShowString(60, 3, (char *)pbuf, 16);

        //Oled显示电池电压
        sprintf((char *)pbuf, "%0.2f", vBat);
        OledShowString(60, 23, (char *)pbuf, 16);

        //Oled显示充电状态
        if (chargeState == 1)
        {
            OledShowString(60, 43, (char *)"ON ", 16);
        }
        else
        {
            OledShowString(60, 43, (char *)"OFF", 16);
        }
        OledRefresh();

        usleep(1000 * 1000);
    }
}

static void BatteryExampleEntry(void)
{
    osThreadAttr_t attr;

    attr.name = "Battey_Task";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = TASK_STACK_SIZE;
    attr.priority = TASK_PRIO;

    if (osThreadNew((osThreadFunc_t)BatteryTask, NULL, &attr) == NULL)
    {
        printf("Falied to create Battery Task!\n");
    }
}
APP_FEATURE_INIT(BatteryExampleEntry);
